/*
 * operations on IDE disk.
 */

#include "fs.h"
#include "lib.h"
#include <mmu.h>

#define IDE_START_A 0x13000000
#define IDE_OFFSET_A (IDE_START_A + 0x0000)
#define IDE_OFFSET_HIGH_A (IDE_START_A + 0x0008)
#define IDE_ID_A (IDE_START_A + 0x0010)
#define IDE_OP_A (IDE_START_A + 0x0020)
#define IDE_STATUS_A (IDE_START_A + 0x0030)
#define IDE_BUFFER_A (IDE_START_A + 0x4000)
#define BUFFER_SIZE 0x0200

// Overview:
// 	read data from IDE disk. First issue a read request through
// 	disk register and then copy data from disk buffer
// 	(512 bytes, a sector) to destination array.
//
// Parameters:
//	diskno: disk number.
// 	secno: start sector number.
// 	dst: destination for data read from IDE disk.
// 	nsecs: the number of sectors to read.
//
// Post-Condition:
// 	If error occurred during read the IDE disk, panic. 
// 	
// Hint: use syscalls to access device registers and buffers
void
ide_read(u_int diskno, u_int secno, void *dst, u_int nsecs)
{
	// 0x200: the size of a sector: 512 bytes.
	int offset_begin = secno * 0x200;
	int offset_end = offset_begin + nsecs * 0x200;
	int offset = 0;
	int diskoff = 0;
	int op = 0;
	int status = 0;

	while ((diskoff = offset_begin + offset) < offset_end) {
            // Your code here
            // error occurred, then panic.
		if (syscall_write_dev((u_int)&diskno, IDE_ID_A, sizeof(u_int)) < 0) {
			user_panic("id write wrong\n");
		}
		if (syscall_write_dev((u_int)&diskoff, IDE_OFFSET_A, sizeof(u_int)) < 0) {
			user_panic("offset write wrong\n");
		}
		if (syscall_write_dev((u_int)&op, IDE_OP_A, sizeof(u_int)) < 0) {
			user_panic("op write wrong\n");
		}

		if (syscall_read_dev((u_int)&status, IDE_STATUS_A, sizeof(u_int)) < 0) {
			user_panic("status read wrong\n");
		}
		if (status == 0) {
			user_panic("fail to read IDE\n");
		}

		if (syscall_read_dev((u_int)dst + offset, IDE_BUFFER_A, BUFFER_SIZE) < 0) {
			user_panic("data read wrong\n");
		}
		offset += BUFFER_SIZE;
	}

}

// Overview:
// 	write data to IDE disk.
//
// Parameters:
//	diskno: disk number.
//	secno: start sector number.
// 	src: the source data to write into IDE disk.
//	nsecs: the number of sectors to write.
//
// Post-Condition:
//	If error occurred during read the IDE disk, panic.
//	
// Hint: use syscalls to access device registers and buffers
void
ide_write(u_int diskno, u_int secno, void *src, u_int nsecs)
{
        // Your code here
	int offset_begin = secno * 0x200;
	int offset_end = offset_begin + nsecs * 0x200;
	int offset = 0;
	int diskoff = 0;
	int op = 1;
	int status = 0;

	// DO NOT DELETE WRITEF !!!
	writef("diskno: %d\n", diskno);

	while ((diskoff = offset_begin + offset) < offset_end) {
            // Your code here
            // error occurred, then panic.
		if (syscall_write_dev((u_int)&diskno, IDE_ID_A, sizeof(u_int)) < 0) {
			user_panic("id write wrong\n");
		}
		if (syscall_write_dev((u_int)&diskoff, IDE_OFFSET_A, sizeof(u_int)) < 0) {
			user_panic("offset write wrong\n");
		}
		if (syscall_write_dev((u_int)src + offset, IDE_BUFFER_A, BUFFER_SIZE) < 0) {
			user_panic("data write wrong\n");
		}
		if (syscall_write_dev((u_int)&op, IDE_OP_A, sizeof(u_int)) < 0) {
			user_panic("op write wrong\n");
		}

		if (syscall_read_dev((u_int)&status, IDE_STATUS_A, sizeof(u_int)) < 0) {
			user_panic("status read wrong\n");
		}
		if (status == 0) {
			user_panic("fail to read IDE\n");
		}

		offset += BUFFER_SIZE;
	}

}

